/* ========================================================================= *
 *                                                                           *
 *                                 SMPL++                                    *
 *                    Copyright (c) 2018, Chongyi Zheng.                     *
 *                          All Rights reserved.                             *
 *                                                                           *
 * ------------------------------------------------------------------------- *
 *                                                                           *
 * This software implements a 3D human skinning model - SMPL: A Skinned      *
 * Multi-Person Linear Model with C++.                                       *
 *                                                                           *
 * For more detail, see the paper published by Max Planck Institute for      *
 * Intelligent Systems on SIGGRAPH ASIA 2015.                                *
 *                                                                           *
 * We provide this software for research purposes only.                      *
 * The original SMPL model is available at http://smpl.is.tue.mpg.           *
 *                                                                           *
 * ========================================================================= */

//=============================================================================
//
//  CLASS Tester IMPLEMENTATIONS
//
//=============================================================================


//===== EXTERNAL MACROS =======================================================


//===== INCLUDES ==============================================================

//----------
#include <fstream>
//----------
#include <xtensor/xarray.hpp>
#include <xtensor/xjson.hpp>
//----------
#include "definition/def.h"
#include "toolbox/Tester.h"
#include "toolbox/TorchEx.hpp"
#include "toolbox/Exception.h"
#include "toolbox/Singleton.hpp"
#include "smpl/BlendShape.h"
#include "smpl/JointRegression.h"
#include "smpl/WorldTransformation.h"
#include "smpl/LinearBlendSkinning.h"
//----------

//===== EXTERNAL FORWARD DECLARATIONS =========================================


//===== NAMESPACES ============================================================

namespace smpl {

//===== INTERNAL MACROS =======================================================


//===== INTERNAL FORWARD DECLARATIONS =========================================


//===== CLASS IMPLEMENTATIONS =================================================

/**Tester
 * 
 * Brief
 * ----------
 * 
 *      Default constructor.
 * 
 * Arguments
 * ----------
 * 
 * 
 * Return
 * ----------
 * 
 * 
 */
Tester::Tester() noexcept(true) :
    m__device(torch::kCPU)
{
}

/**Tester (overload)
 * 
 * Brief
 * ----------
 * 
 *      Copy constructor.
 * 
 * Arguments
 * ----------
 * 
 *      @tester: - const Testet & -
 *          The tester to copy with.
 * 
 * Return
 * ----------
 * 
 * 
 */
Tester::Tester(const Tester &tester) noexcept(true) :
    m__device(torch::kCPU)
{
    *this = tester;
}

/**~Tester
 * 
 * Brief
 * ----------
 * 
 *      Destructor.
 * 
 * Arguments
 * ----------
 * 
 * 
 * Return
 * ----------
 * 
 * 
 */
Tester::~Tester() noexcept(true)
{
}

/**operator=
 * 
 * Brief
 * ----------
 * 
 *      Assignment operator is used to copy an tester.
 * 
 * Arguments
 * ----------
 * 
 *      @tester: - const Tester & -
 *          The tester to copy with.
 * 
 * Return
 * ----------
 *
 *      @*this: - Tester & -
 *          Current instantiation. 
 * 
 */
Tester &Tester::operator=(const Tester &tester) noexcept(false)
{
    if (tester.m__device.has_index()) {
        m__device = tester.m__device;
    }
    else {
        throw smpl_error("Tester", "Failed to fetch device index!");
    }

    return *this;
}

/**setDevice
 * 
 * Brief
 * ----------
 * 
 *      Set the torch device.
 * 
 * Arguments
 * ----------
 * 
 * 
 * Return
 * ----------
 * 
 */
void Tester::setDevice(const torch::Device& device) noexcept(false)
{
    if (device.has_index()) {
        m__device = device;
    }
    else {
        throw smpl_error("Tester", "Failed to fetch device index!");
    }

    return;
}

/**singleton
 * 
 * Brief
 * ----------
 * 
 *      Test the <Singleton> module.
 * 
 * Arguments
 * ----------
 * 
 * 
 * Return
 * ----------
 * 
 * 
 */
void Tester::singleton() noexcept(true)
{
    std::cout << "---------- <Singleton> Test ----------" << std::endl;

    const int *intPtr1 = Singleton<int>::get();
    const int *intPtr2 = Singleton<int>::get();
    const float *floatPtr1 = Singleton<float>::get();
    const float *floatPtr2 = Singleton<float>::get();
    assert(intPtr1 == intPtr2);
    assert(floatPtr1 == floatPtr2);

    std::cout << "intPtr1: " << intPtr1 << std::endl;
    std::cout << "intPtr2: " << intPtr2 << std::endl;
    std::cout << std::endl;

    std::cout << "floatPtr1: " << floatPtr1 << std::endl;
    std::cout << "floatPtr2: " << floatPtr2 << std::endl;
    std::cout << std::endl;

    Singleton<int>::destroy();
    Singleton<float>::destroy();

    std::cout << "PASS!" << std::endl;
    std::cout << "--------------------------------------" << std::endl;

    return;
}

/**import
 * 
 * Brief
 * ----------
 * 
 *      Test file reading module.
 * 
 * Arguments
 * ----------
 * 
 * 
 * Return
 * ----------
 * 
 * 
 */
void Tester::import() noexcept(true)
{
    std::cout << "---------- Import Test ----------" << std::endl;

    std::ifstream file("../data/smpl_female.json");

    nlohmann::json model;
    file >> model;

    xt::xarray<int64_t> kinematicTree_;
    xt::from_json(model["kinematic_tree"], kinematicTree_);

    /**correct result 
     * 
     * - kinematicTree: [2, 24]
     *      [
     *          [4294967295, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8,
     *          9, 9, 9, 12, 13, 14, 16, 17, 18, 19, 20, 21],
     *          [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
     *          12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]
     *      ]
     */
    torch::Tensor kinematicTree = torch::from_blob(
        kinematicTree_.data(), {2, JOINT_NUM}, torch::kInt64
    ).to(m__device);

    std::cout << "kinematic tree: " 
        << kinematicTree.sizes() << std::endl;
    std::cout << kinematicTree << std::endl;

    std::cout << "PASS!" << std::endl;
    std::cout << "---------------------------------" << std::endl;

    return;
}

/**blendShape
 * 
 * Brief
 * ----------
 * 
 *      Test the <BlendShape> module.
 * 
 * Arguments
 * ----------
 * 
 * 
 * Return
 * ----------
 * 
 * 
 * Notes
 * ----------
 * 
 *      We need to set both BATCH_SIZE and VERTEX_NUM in "definition/def.h" to
 *      1 to make it compatible with this test.
 *      This kind of random number is generated by numpy with random seed 0.
 * 
 */
void Tester::blendShape() noexcept(true)
{
    int batchSize = BATCH_SIZE;
    int vertexNum = VERTEX_NUM;
    BATCH_SIZE = 1;
    VERTEX_NUM = 1;

    std::cout << "---------- <BlendShape> Test ----------" << std::endl;

    xt::xarray<float> theta_ {
        {
            {0.79172504, 0.52889492, 0.56804456},
            {0.92559664, 0.07103606, 0.0871293 },
            {0.0202184 , 0.83261985, 0.77815675},
            {0.87001215, 0.97861834, 0.79915856},
            {0.46147936, 0.78052918, 0.11827443},
            {0.63992102, 0.14335329, 0.94466892},
            {0.52184832, 0.41466194, 0.26455561},
            {0.77423369, 0.45615033, 0.56843395},
            {0.0187898 , 0.6176355 , 0.61209572},
            {0.616934  , 0.94374808, 0.6818203 },
            {0.3595079 , 0.43703195, 0.6976312 },
            {0.06022547, 0.66676672, 0.67063787},
            {0.21038256, 0.1289263 , 0.31542835},
            {0.36371077, 0.57019677, 0.43860151},
            {0.98837384, 0.10204481, 0.20887676},
            {0.16130952, 0.65310833, 0.2532916 },
            {0.46631077, 0.24442559, 0.15896958},
            {0.11037514, 0.65632959, 0.13818295},
            {0.19658236, 0.36872517, 0.82099323},
            {0.09710128, 0.83794491, 0.09609841},
            {0.97645947, 0.4686512 , 0.97676109},
            {0.60484552, 0.73926358, 0.03918779},
            {0.28280696, 0.12019656, 0.2961402 },
            {0.11872772, 0.31798318, 0.41426299}
        }
    };// (1, 24, 3)
    torch::Tensor theta = torch::from_blob(theta_.data(), 
        {BATCH_SIZE, JOINT_NUM, 3}).to(m__device);


    xt::xarray<float> beta_ {
        {
            0.5488135  , 0.71518937, 0.60276338, 0.54488318, 0.4236548 , 
            0.64589411 , 0.43758721, 0.891773  , 0.96366276, 0.38344152
        }
    };// (1, 10)
    torch::Tensor beta = torch::from_blob(beta_.data(),
        {BATCH_SIZE, SHAPE_BASIS_DIM}).to(m__device);

    xt::xarray<float> poseBlendBasis_ {
        {
            {0.0641475 , 0.69247212, 0.56660145, 0.26538949, 0.52324805,
            0.09394051, 0.5759465 , 0.9292962 , 0.31856895, 0.66741038,
            0.13179786, 0.7163272 , 0.28940609, 0.18319136, 0.58651293,
            0.02010755, 0.82894003, 0.00469548, 0.67781654, 0.27000797,
            0.73519402, 0.96218855, 0.24875314, 0.57615733, 0.59204193,
            0.57225191, 0.22308163, 0.95274901, 0.44712538, 0.84640867,
            0.69947928, 0.29743695, 0.81379782, 0.39650574, 0.8811032 ,
            0.58127287, 0.88173536, 0.69253159, 0.72525428, 0.50132438,
            0.95608363, 0.6439902 , 0.42385505, 0.60639321, 0.0191932 ,
            0.30157482, 0.66017354, 0.29007761, 0.61801543, 0.4287687 ,
            0.13547406, 0.29828233, 0.56996491, 0.59087276, 0.57432525,
            0.65320082, 0.65210327, 0.43141844, 0.8965466 , 0.36756187,
            0.43586493, 0.89192336, 0.80619399, 0.70388858, 0.10022689,
            0.91948261, 0.7142413 , 0.99884701, 0.1494483 , 0.86812606,
            0.16249293, 0.61555956, 0.12381998, 0.84800823, 0.80731896,
            0.56910074, 0.4071833 , 0.069167  , 0.69742877, 0.45354268,
            0.7220556 , 0.86638233, 0.97552151, 0.85580334, 0.01171408,
            0.35997806, 0.72999056, 0.17162968, 0.52103661, 0.05433799,
            0.19999652, 0.01852179, 0.7936977 , 0.22392469, 0.34535168,
            0.92808129, 0.7044144 , 0.03183893, 0.16469416, 0.6214784 ,
            0.57722859, 0.23789282, 0.934214  , 0.61396596, 0.5356328 ,
            0.58990998, 0.73012203, 0.311945  , 0.39822106, 0.20984375,
            0.18619301, 0.94437239, 0.7395508 , 0.49045881, 0.22741463,
            0.25435648, 0.05802916, 0.43441663, 0.31179588, 0.69634349,
            0.37775184, 0.17960368, 0.02467873, 0.06724963, 0.67939277,
            0.45369684, 0.53657921, 0.89667129, 0.99033895, 0.21689698,
            0.6630782 , 0.26332238, 0.020651  , 0.75837865, 0.32001715,
            0.38346389, 0.58831711, 0.83104846, 0.62898184, 0.87265066,
            0.27354203, 0.79804683, 0.18563594, 0.95279166, 0.68748828,
            0.21550768, 0.94737059, 0.73085581, 0.25394164, 0.21331198,
            0.51820071, 0.02566272, 0.20747008, 0.42468547, 0.37416998,
            0.46357542, 0.27762871, 0.58678435, 0.86385561, 0.11753186,
            0.51737911, 0.13206811, 0.71685968, 0.3960597 , 0.56542131,
            0.18327984, 0.14484776, 0.48805628, 0.35561274, 0.94043195,
            0.76532525, 0.74866362, 0.90371974, 0.08342244, 0.55219247,
            0.58447607, 0.96193638, 0.29214753, 0.24082878, 0.10029394,
            0.01642963, 0.92952932, 0.66991655, 0.78515291, 0.28173011,
            0.58641017, 0.06395527, 0.4856276 , 0.97749514, 0.87650525,
            0.33815895, 0.96157015, 0.23170163, 0.94931882, 0.9413777 ,
            0.79920259, 0.63044794, 0.87428797, 0.29302028, 0.84894356,
            0.61787669, 0.01323686, 0.34723352, 0.14814086, 0.98182939,
            0.47837031, 0.49739137},

            {0.63947252, 0.36858461, 0.13690027, 0.82211773, 0.18984791,
            0.51131898, 0.22431703, 0.09784448, 0.86219152, 0.97291949,
            0.96083466, 0.9065555 , 0.77404733, 0.33314515, 0.08110139,
            0.40724117, 0.23223414, 0.13248763, 0.05342718, 0.72559436,
            0.01142746, 0.77058075, 0.14694665, 0.07952208, 0.08960303,
            0.67204781, 0.24536721, 0.42053947, 0.55736879, 0.86055117,
            0.72704426, 0.27032791, 0.1314828 , 0.05537432, 0.30159863,
            0.26211815, 0.45614057, 0.68328134, 0.69562545, 0.28351885,
            0.37992696, 0.18115096, 0.78854551, 0.05684808, 0.69699724,
            0.7786954 , 0.77740756, 0.25942256, 0.37381314, 0.58759964,
            0.2728219 , 0.3708528 , 0.19705428, 0.45985588, 0.0446123 ,
            0.79979588, 0.07695645, 0.51883515, 0.3068101 , 0.57754295,
            0.95943334, 0.64557024, 0.03536244, 0.43040244, 0.51001685,
            0.53617749, 0.68139251, 0.2775961 , 0.12886057, 0.39267568,
            0.95640572, 0.18713089, 0.90398395, 0.54380595, 0.45691142,
            0.88204141, 0.45860396, 0.72416764, 0.39902532, 0.90404439,
            0.69002502, 0.69962205, 0.3277204 , 0.75677864, 0.63606106,
            0.24002027, 0.16053882, 0.79639147, 0.9591666 , 0.45813883,
            0.59098417, 0.85772264, 0.45722345, 0.95187448, 0.57575116,
            0.82076712, 0.90884372, 0.81552382, 0.15941446, 0.62889844,
            0.39843426, 0.06271295, 0.42403225, 0.25868407, 0.84903831,
            0.03330463, 0.95898272, 0.35536885, 0.35670689, 0.0163285 ,
            0.18523233, 0.4012595 , 0.92929142, 0.09961493, 0.94530153,
            0.86948853, 0.4541624 , 0.32670088, 0.23274413, 0.61446471,
            0.03307459, 0.01560606, 0.42879572, 0.06807407, 0.25194099,
            0.22116092, 0.25319119, 0.13105523, 0.01203622, 0.1154843 ,
            0.61848026, 0.97425621, 0.990345  , 0.4090541 , 0.16295443,
            0.63876176, 0.49030535, 0.98940978, 0.06530421, 0.78323444,
            0.2883985 , 0.24141862, 0.66250457, 0.24606318, 0.66585912,
            0.51730852, 0.42408899, 0.55468781, 0.28705152, 0.70657471,
            0.41485687, 0.36054556, 0.82865691, 0.92496691, 0.04600731,
            0.23262699, 0.34851937, 0.81496648, 0.98549143, 0.9689717 ,
            0.90494835, 0.29655627, 0.99201124, 0.24942004, 0.10590615,
            0.95095261, 0.23342026, 0.68976827, 0.05835636, 0.7307091 ,
            0.88172021, 0.2724369 , 0.3790569 , 0.37429618, 0.74878826,
            0.23780724, 0.1718531 , 0.44929165, 0.30446841, 0.83918912,
            0.23774183, 0.50238946, 0.9425836 , 0.6339977 , 0.86728941,
            0.94020969, 0.75076486, 0.69957506, 0.96796557, 0.99440079,
            0.45182168, 0.07086978, 0.29279403, 0.15235471, 0.41748637,
            0.13128933, 0.6041178 , 0.38280806, 0.89538588, 0.96779467,
            0.5468849 , 0.27482357, 0.59223042, 0.89676116, 0.40673335,
            0.55207828, 0.27165277},
            
            {0.45544415, 0.40171354, 0.24841347, 0.50586638, 0.31038083,
            0.37303486, 0.52497044, 0.75059502, 0.33350747, 0.92415877,
            0.86231855, 0.0486903 , 0.25364252, 0.44613551, 0.10462789,
            0.34847599, 0.74009753, 0.68051448, 0.62238443, 0.7105284 ,
            0.20492369, 0.34169811, 0.67624248, 0.87923476, 0.54367805,
            0.28269965, 0.03023526, 0.71033683, 0.0078841 , 0.37267907,
            0.53053721, 0.92211146, 0.08949455, 0.40594232, 0.0243132 ,
            0.34261098, 0.62223106, 0.27906795, 0.20974995, 0.11570323,
            0.57714024, 0.69527001, 0.67195714, 0.94886102, 0.00270321,
            0.64719665, 0.60039224, 0.58873961, 0.96277032, 0.01687167,
            0.69648243, 0.81367865, 0.5098072 , 0.33396487, 0.79084016,
            0.09724293, 0.44203564, 0.51995237, 0.69395641, 0.09088573,
            0.2277595 , 0.41030156, 0.62329467, 0.88696078, 0.61882617,
            0.13346147, 0.98058013, 0.87178573, 0.50272076, 0.92234798,
            0.54138079, 0.92330607, 0.82989737, 0.96828641, 0.91978281,
            0.03603382, 0.174772  , 0.38913468, 0.9521427 , 0.30002892,
            0.16046764, 0.88630467, 0.44639442, 0.90787559, 0.16023047,
            0.66111751, 0.44026375, 0.07648677, 0.69646314, 0.24739876,
            0.03961552, 0.0599443 , 0.06107854, 0.90773296, 0.73988392,
            0.89806236, 0.67258231, 0.52893993, 0.30444636, 0.99796225,
            0.36218906, 0.47064895, 0.37824517, 0.97952693, 0.17465839,
            0.327988  , 0.68034867, 0.06320762, 0.60724937, 0.4776465 ,
            0.28399998, 0.23841328, 0.51451274, 0.36792758, 0.45651989,
            0.33747738, 0.97049369, 0.13343943, 0.09680395, 0.34339173,
            0.5910269 , 0.65917647, 0.39725675, 0.99927799, 0.351893  ,
            0.72140667, 0.63758269, 0.81305386, 0.97622566, 0.88979366,
            0.76456197, 0.69824848, 0.33549817, 0.14768558, 0.062636  ,
            0.2419017 , 0.43228148, 0.52199627, 0.77308355, 0.95874092,
            0.11732048, 0.10700414, 0.58969472, 0.74539807, 0.84815038,
            0.93583208, 0.98342624, 0.39980169, 0.38033518, 0.14780868,
            0.68493444, 0.65676196, 0.8620626 , 0.09725799, 0.49777691,
            0.58108193, 0.24155704, 0.16902541, 0.85958084, 0.05853492,
            0.4706209 , 0.115834  , 0.45705876, 0.97996233, 0.42370635,
            0.85712492, 0.11731556, 0.27125208, 0.40379274, 0.39981214,
            0.67138348, 0.34471813, 0.71376687, 0.6391869 , 0.39916115,
            0.43176013, 0.6145277 , 0.07004219, 0.82240674, 0.65342116,
            0.72634246, 0.536923  , 0.11047711, 0.40503561, 0.40537358,
            0.32104299, 0.02995032, 0.73725424, 0.10978446, 0.60630813,
            0.7032175 , 0.63478632, 0.95914225, 0.10329816, 0.86716716,
            0.02919023, 0.53491685, 0.40424362, 0.52418386, 0.36509988,
            0.19056691, 0.0191229 , 0.51814981, 0.84277686, 0.37321596,
            0.22286382, 0.080532  }
        }
    };// (1, 3, 207)
    torch::Tensor poseBlendBasis = torch::from_blob(poseBlendBasis_.data(), 
        {BATCH_SIZE, 3, POSE_BASIS_DIM}).to(m__device);

    xt::xarray<float> shapeBlendBasis_ {
        {
            {0.08531092, 0.22139645, 0.10001406, 0.2650397 , 0.06614946,
            0.06560487, 0.85627618, 0.16212026, 0.55968241, 0.77345554},
            
            {0.45640957, 0.15336888, 0.19959614, 0.43298421, 0.52823409,
            0.34944029, 0.7814796 , 0.75102165, 0.92721181, 0.02895255},
            
            {0.89569129, 0.39256879, 0.8783725 , 0.69078478, 0.98734876,
            0.75928245, 0.36454463, 0.50106317, 0.37638916, 0.36491184}
        }
    };// (1, 3, 10)
    torch::Tensor shapeBlendBasis = torch::from_blob(shapeBlendBasis_.data(),
        {BATCH_SIZE, 3, SHAPE_BASIS_DIM}).to(m__device);

    /**correct result
     *
     * - shapeBlendShape: [1, 3]
     *      [
     *          [1.835449, 3.082224, 3.695877]
     *      ]
     * 
     * - poseBlendShape: [1, 3]
     *      [
     *          [
     *              [0.912995, -1.879041, -3.56463]
     *          ]
     *      ]
     * 
     * - poseRotation: [5, 3, 3]
     *      [
     *          [
     *              [ 0.728415, -0.269833,  0.629764],
     *              [ 0.647397,  0.571931, -0.503758],
     *              [-0.224251,  0.774652,  0.591292]
     *          ],
     *          [
     *              [ 0.994126, -0.044481,  0.098667],
     *              [ 0.105604,  0.598255, -0.794316],
     *              [-0.023696,  0.80007 ,  0.599438],
     *          ],
     *          [
     *              [ 0.41794 , -0.612729,  0.670738],
     *              [ 0.627818,  0.728445,  0.274249],
     *              [-0.656636,  0.306481,  0.689129]
     *          ],
     *          [
     *              [ 0.346577, -0.172097,  0.922099],
     *              [ 0.869102,  0.428758, -0.246636],
     *              [-0.352912,  0.886876,  0.298167]
     *          ],
     *          [
     *              [ 0.70951 ,  0.065427,  0.701652],
     *              [ 0.270361,  0.894214, -0.356772],
     *              [-0.650769,  0.442832,  0.616765]
     *          ]
     *      ]
     * 
     * - restPoseRotation: [1, 3, 3]
     *      [
     *          [1., 0., 0.],
     *          [0., 1., 0.],
     *          [0., 0., 1.]
     *      ]
     */

    torch::Tensor shapeBlendShape, poseBlendShape;
    torch::Tensor poseRotation, restPoseRotation;
    try {
        BlendShape blendShape;
        blendShape.setDevice(m__device);

        blendShape.setTheta(theta);
        blendShape.setBeta(beta);
        blendShape.setPoseBlendBasis(poseBlendBasis);
        blendShape.setShapeBlendBasis(shapeBlendBasis);

        blendShape.blend();

        shapeBlendShape = blendShape.getShapeBlendShape();// (1, 1, 3)
        poseBlendShape = blendShape.getPoseBlendShape();// (1, 1, 3)
        poseRotation = blendShape.getPoseRotation();// (1, 24, 3, 3)
        restPoseRotation = blendShape.getRestPoseRotation();// (1, 24, 3, 3)
    }
    catch(Exception &e) {
        std::cerr << e.what() << std::endl;
    }

    std::cout << "shape blend shape: " 
        << shapeBlendShape.sizes() << std::endl;// (1, 1, 3)
    std::cout << shapeBlendShape << std::endl;
    std::cout << std::endl;

    std::cout << "pose blend shape: "
        << poseBlendShape.sizes() << std::endl;// (1, 3, 3)
    std::cout << poseBlendShape << std::endl;
    std::cout << std::endl;

    torch::Tensor poseRotSlice = TorchEx::indexing(poseRotation,
        torch::IntList({0}),
        torch::IntList({0, 5}),
        torch::IntList(),
        torch::IntList()
    );
    std::cout << "first five pose rotation: "
        << poseRotSlice.sizes() << std::endl;// (5, 3, 3)
    std::cout << poseRotSlice << std::endl;// the first five rotation
    std::cout << std::endl;
    
    torch::Tensor restRotSlice = TorchEx::indexing(restPoseRotation,
        torch::IntList(),
        torch::IntList({0}),
        torch::IntList(),
        torch::IntList()
    );
    std::cout << "first rest pose rotation: "
        << restRotSlice.sizes() << std::endl;// (1, 3, 3)
    std::cout << restRotSlice << std::endl;// the first rotation
    std::cout << std::endl;

    std::cout << "PASS!" << std::endl;
    std::cout << "---------------------------------------" << std::endl;

    BATCH_SIZE = batchSize;
    VERTEX_NUM = vertexNum;

    return;
}

/**jointRegression
 * 
 * Brief
 * ----------
 * 
 *      Test the <JointRegression> module.
 * 
 * Arguments
 * ----------
 * 
 * 
 * Return
 * ----------
 * 
 * 
 * Notes
 * ----------
 * 
 *      We need to set BATCH_SIZE in "definition/def.h" to 1 and VERTEX_NUM to
 *      5 to make it compatible with this test.
 *      This kind of random number is generated by numpy with random seed 0.
 * 
 */
void Tester::jointRegression() noexcept(true)
{
    int batchSize = BATCH_SIZE;
    int vertexNum = VERTEX_NUM;
    BATCH_SIZE = 1;
    VERTEX_NUM = 5;

    std::cout << "---------- <JointRegression> Test ----------" << std::endl;

    xt::xarray<float> templateShape_ {
        {0.5488135 , 0.71518937, 0.60276338},
        {0.54488318, 0.4236548 , 0.64589411},
        {0.43758721, 0.891773  , 0.96366276},
        {0.38344152, 0.79172504, 0.52889492},
        {0.56804456, 0.92559664, 0.07103606}
    };// (5, 3)
    torch::Tensor templateShape = torch::from_blob(templateShape_.data(),
        {VERTEX_NUM, 3}).to(m__device);

    xt::xarray<float> jointRegressor_ {
        {0.0871293 , 0.0202184 , 0.83261985, 0.77815675, 0.87001215},
        {0.97861834, 0.79915856, 0.46147936, 0.78052918, 0.11827443},
        {0.63992102, 0.14335329, 0.94466892, 0.52184832, 0.41466194},
        {0.26455561, 0.77423369, 0.45615033, 0.56843395, 0.0187898 },
        {0.6176355 , 0.61209572, 0.616934  , 0.94374808, 0.6818203 },
        {0.3595079 , 0.43703195, 0.6976312 , 0.06022547, 0.66676672},
        {0.67063787, 0.21038256, 0.1289263 , 0.31542835, 0.36371077},
        {0.57019677, 0.43860151, 0.98837384, 0.10204481, 0.20887676},
        {0.16130952, 0.65310833, 0.2532916 , 0.46631077, 0.24442559},
        {0.15896958, 0.11037514, 0.65632959, 0.13818295, 0.19658236},
        {0.36872517, 0.82099323, 0.09710128, 0.83794491, 0.09609841},
        {0.97645947, 0.4686512 , 0.97676109, 0.60484552, 0.73926358},
        {0.03918779, 0.28280696, 0.12019656, 0.2961402 , 0.11872772},
        {0.31798318, 0.41426299, 0.0641475 , 0.69247212, 0.56660145},
        {0.26538949, 0.52324805, 0.09394051, 0.5759465 , 0.9292962 },
        {0.31856895, 0.66741038, 0.13179786, 0.7163272 , 0.28940609},
        {0.18319136, 0.58651293, 0.02010755, 0.82894003, 0.00469548},
        {0.67781654, 0.27000797, 0.73519402, 0.96218855, 0.24875314},
        {0.57615733, 0.59204193, 0.57225191, 0.22308163, 0.95274901},
        {0.44712538, 0.84640867, 0.69947928, 0.29743695, 0.81379782},
        {0.39650574, 0.8811032 , 0.58127287, 0.88173536, 0.69253159},
        {0.72525428, 0.50132438, 0.95608363, 0.6439902 , 0.42385505},
        {0.60639321, 0.0191932 , 0.30157482, 0.66017354, 0.29007761},
        {0.61801543, 0.4287687 , 0.13547406, 0.29828233, 0.56996491}
    };// (24, 5)
    torch::Tensor jointRegressor = torch::from_blob(jointRegressor_.data(),
        {JOINT_NUM, VERTEX_NUM}).to(m__device);

    xt::xarray<float> shapeBlendShape_ {
        {
            {0.1494483 , 0.86812606, 0.16249293},
            {0.61555956, 0.12381998, 0.84800823},
            {0.80731896, 0.56910074, 0.4071833 },
            {0.069167  , 0.69742877, 0.45354268},
            {0.7220556 , 0.86638233, 0.97552151}
        }
    };// (1, 5, 3)
    torch::Tensor shapeBlendShape = torch::from_blob(shapeBlendShape_.data(),
        {BATCH_SIZE, VERTEX_NUM, 3}).to(m__device);

    xt::xarray<float> poseBlendShape_ {
        {
            {0.59087276, 0.57432525, 0.65320082},
            {0.65210327, 0.43141844, 0.8965466 },
            {0.36756187, 0.43586493, 0.89192336},
            {0.80619399, 0.70388858, 0.10022689},
            {0.91948261, 0.7142413 , 0.99884701}
        }
    };// (1, 5, 3)
    torch::Tensor poseBlendShape = torch::from_blob(poseBlendShape_.data(),
        {BATCH_SIZE, VERTEX_NUM, 3}).to(m__device);

    /**correct results
     * 
     * - restShape: (1, 5, 3)
     *      [
     *          [
     *              [1.289135, 2.157641, 1.418457],
     *              [1.812546, 0.978893, 2.390449],
     *              [1.612468, 1.896739, 2.262769],
     *              [1.258803, 2.193042, 1.082664],
     *              [2.209583, 2.50622 , 2.045405]
     *          ]
     *      ]
     * 
     * - joints: (1, 24, 3)
     *      [
     *          [2.595438, 4.083213, 2.913282],
     *          [2.691068, 4.035417, 3.465978],
     *          [2.560358, 3.991899, 2.945506],
     *          [1.932566, 2.389283, 2.56251 ],
     *          [3.216363, 4.841475, 3.87352 ],
     *          [2.514121, 3.112146, 2.641321],
     *          [1.484908, 2.486839, 1.694772],
     *          [2.45321 , 3.113077, 2.765337],
     *          [1.712245, 2.115405, 2.160274],
     *          [1.372309, 1.828988, 1.52776 ],
     *          [1.834302, 2.595169, 2.565565],
     *          [3.669125, 5.454995, 4.154255],
     *          [0.792384, 1.046224, 1.03244 ],
     *          [1.827013, 2.870513, 2.223435],
     *          [2.369021, 3.366848, 2.651944],
     *          [1.858591, 2.647657, 2.428134],
     *          [1.214805, 1.883359, 1.863242],
     *          [2.458281, 4.173653, 3.135531],
     *          [3.13185 , 4.111864, 3.326101],
     *          [3.349709, 4.094417, 3.709395],
     *          [3.315481, 4.513383, 4.00757 ],
     *          [3.116701, 4.538026, 3.690847],
     *          [1.494156, 2.914095, 1.858294],
     *          [1.968068, 2.876717, 2.188738]
     *      ]
     * 
     */

    torch::Tensor restShape, joints;
    try {
        JointRegression jointRegression;
        jointRegression.setDevice(m__device);

        jointRegression.setShapeBlendShape(shapeBlendShape);
        jointRegression.setPoseBlendShape(poseBlendShape);
        jointRegression.setTemplateRestShape(templateShape);
        jointRegression.setJointRegressor(jointRegressor);

        jointRegression.regress();

        restShape = jointRegression.getRestShape();
        joints = jointRegression.getJoint();
    }
    catch(std::exception &e) {
        std::cerr << e.what() << std::endl;
    }

    std::cout << "deformed shape in rest pose: ";
    std::cout << restShape.sizes() << std::endl;// (1, 5, 3)
    std::cout << restShape << std::endl;
    std::cout << std::endl;

    std::cout << "joints of deformed shape: ";
    std::cout << joints.sizes() << std::endl;// (1, 24, 3)
    std::cout << joints << std::endl;
    std::cout << std::endl;

    std::cout << "PASS!" << std::endl;
    std::cout << "--------------------------------------------" << std::endl;

    BATCH_SIZE = batchSize;
    VERTEX_NUM = vertexNum;

    return;
}

/**worldTransformation
 * 
 * Brief
 * ----------
 * 
 *      Test the <WorldTransformation> module.
 * 
 * Arguments
 * ----------
 * 
 * 
 * Return
 * ----------
 * 
 * 
 * Notes
 * ----------
 * 
 *      We need to set BATCH_SIZE in "definition/def.h" to 1 to make it
 *      compatible with this test.
 *      This kind of random number is generated by numpy with random seed 0.
 * 
 */
void Tester::worldTransformation() noexcept(true)
{
    int batchSize = BATCH_SIZE;
    BATCH_SIZE = 1;

    std::cout << "---------- <WorldTransformation> Test ----------" << std::endl;

    /**
     * 
     * This array is exactly the kinematic tree of SMPL.
     * 
     *      first row - ancestor index
     *      second row - joint indices
     * 
     *      Note: Joint with ancestor index as 4294967295 is indeed root at
     *            the belly button. 
     * 
     */
    xt::xarray<int64_t> kineTree_ {
        {4294967295, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8,
        9, 9, 9, 12, 13, 14, 16, 17, 18, 19, 20, 21},
        {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
        12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}
    };// (2, 24)
    torch::Tensor kineTree = torch::from_blob(kineTree_.data(),
        {2, JOINT_NUM}, torch::kInt64).to(m__device);

    xt::xarray<float> joints_ {
        {
            {0.5488135 , 0.71518937, 0.60276338},
            {0.54488318, 0.4236548 , 0.64589411},
            {0.43758721, 0.891773  , 0.96366276},
            {0.38344152, 0.79172504, 0.52889492},
            {0.56804456, 0.92559664, 0.07103606},
            {0.0871293 , 0.0202184 , 0.83261985},
            {0.77815675, 0.87001215, 0.97861834},
            {0.79915856, 0.46147936, 0.78052918},
            {0.11827443, 0.63992102, 0.14335329},
            {0.94466892, 0.52184832, 0.41466194},
            {0.26455561, 0.77423369, 0.45615033},
            {0.56843395, 0.0187898 , 0.6176355 },
            {0.61209572, 0.616934  , 0.94374808},
            {0.6818203 , 0.3595079 , 0.43703195},
            {0.6976312 , 0.06022547, 0.66676672},
            {0.67063787, 0.21038256, 0.1289263 },
            {0.31542835, 0.36371077, 0.57019677},
            {0.43860151, 0.98837384, 0.10204481},
            {0.20887676, 0.16130952, 0.65310833},
            {0.2532916 , 0.46631077, 0.24442559},
            {0.15896958, 0.11037514, 0.65632959},
            {0.13818295, 0.19658236, 0.36872517},
            {0.82099323, 0.09710128, 0.83794491},
            {0.09609841, 0.97645947, 0.4686512 }
        }
    };// (1, 24, 3)
    torch::Tensor joints = torch::from_blob(joints_.data(),
        {BATCH_SIZE, JOINT_NUM, 3}).to(m__device);

    xt::xarray<float> poseRotation_ {
        {
            {
                {0.95627849, 0.89187929, 0.90854612},
                {0.03836603, 0.41701503, 0.14772014},
                {0.28993016, 0.17507081, 0.39079753}
            },
            {
                {0.58499362, 0.10064153, 0.54457918},
                {0.80011548, 0.41637173, 0.41149671},
                {0.13265631, 0.90360714, 0.73082417}
            },
            {
                {0.32537401, 0.91710756, 0.15341195},
                {0.73162891, 0.39768113, 0.21323369},
                {0.59904164, 0.02763035, 0.96488143}
            },
            {
                {0.00502689, 0.51447925, 0.39713296},
                {0.78708538, 0.73032452, 0.36587094},
                {0.61682359, 0.44937423, 0.84167919}
            },
            {
                {0.18665207, 0.7642271 , 0.43332029},
                {0.70818889, 0.56107224, 0.28825352},
                {0.68090344, 0.31804854, 0.85389896}
            },
            {
                {0.51405964, 0.80209599, 0.52180655},
                {0.64139231, 0.45604417, 0.72038693},
                {0.56952489, 0.38557196, 0.45690327}
            },
            {
                {0.05984255, 0.4023277 , 0.67928159},
                {0.90443419, 0.8244877 , 0.44117897},
                {0.42239515, 0.39793523, 0.58646196}
            },
            {
                {0.61958306, 0.68355122, 0.45891009},
                {0.68378874, 0.51346619, 0.6298741 },
                {0.38542157, 0.51875832, 0.62662601}
            },
            {
                {0.65439811, 0.53069018, 0.09855839},
                {0.74635595, 0.53849551, 0.98221896},
                {0.12130913, 0.65451548, 0.15978788}
            },
            {
                {0.60492718, 0.13627062, 0.81201472},
                {0.79337436, 0.62632629, 0.3899005 },
                {0.06797229, 0.76755827, 0.43429217}
            },
            {
                {0.54019544, 0.98085134, 0.83875517},
                {0.64025688, 0.01326178, 0.3095098 },
                {0.54613187, 0.1943059 , 0.44798822}
            },
            {
                {0.04445216, 0.26118456, 0.05332922},
                {0.64929854, 0.29243343, 0.99436014},
                {0.75923343, 0.9199268 , 0.09167282}
            },
            {
                {0.27052909, 0.49025286, 0.51769376},
                {0.39076631, 0.73695414, 0.55064207},
                {0.87983846, 0.46535012, 0.65481791}
            },
            {
                {0.51109183, 0.37932067, 0.25915189},
                {0.30505931, 0.89955053, 0.9133271 },
                {0.80356951, 0.21662106, 0.31412402}
            },
            {
                {0.0829945 , 0.74951041, 0.40556339},
                {0.99592475, 0.65174516, 0.23361654},
                {0.03529602, 0.11602755, 0.88370903}
            },
            {
                {0.40483631, 0.92653125, 0.66487067},
                {0.88368515, 0.37452408, 0.49166429},
                {0.23496407, 0.03565885, 0.56232839}
            },
            {
                {0.34351363, 0.35307573, 0.5505034 },
                {0.89206617, 0.57913725, 0.81656158},
                {0.29362619, 0.73480444, 0.17370431}
            },
            {
                {0.70035022, 0.60877291, 0.64513862},
                {0.69636546, 0.64717498, 0.76019362},
                {0.15679513, 0.45886827, 0.0768233 }
            },
            {
                {0.20703653, 0.81542342, 0.4314793 },
                {0.4626067 , 0.53306498, 0.67665851},
                {0.86205042, 0.22566872, 0.59662289}
            },
            {
                {0.17411446, 0.87321991, 0.3842784 },
                {0.74543378, 0.22325653, 0.14053908},
                {0.64343814, 0.43317839, 0.9124576 }
            },
            {
                {0.6211688 , 0.76780402, 0.81942615},
                {0.06770901, 0.56630987, 0.52995963},
                {0.78074631, 0.2996166 , 0.21836571}
            },
            {
                {0.11194162, 0.02085178, 0.85598015},
                {0.74771759, 0.99648219, 0.25943816},
                {0.65451316, 0.08116926, 0.44720223}
            },
            {
                {0.58771193, 0.72523405, 0.28447649},
                {0.57813715, 0.19171352, 0.79861522},
                {0.56599658, 0.66127263, 0.53036483}
            },
            {
                {0.80893773, 0.28595511, 0.82066083},
                {0.57169238, 0.0129177 , 0.33566536},
                {0.1370678 , 0.95815594, 0.46243331}
            }
        }
    };// (1, 24, 3, 3)
    torch::Tensor poseRotation = torch::from_blob(poseRotation_.data(),
        {BATCH_SIZE, JOINT_NUM, 3, 3});

    /**correct results
     * 
     * - transformations: (1, 5, 4, 4)
     *      [
     *          [
     *              [ 0.956278,  0.891879,  0.908546, -1.161506],
     *              [ 0.038366,  0.417015,  0.14772 ,  0.306849],
     *              [ 0.28993 ,  0.175071,  0.390798,  0.082879],
     *              [ 0.      ,  0.      ,  0.      ,  1.      ]
     *          ],
     *          [
     *              [ 1.393548,  1.288563,  1.551762, -1.983273],
     *              [ 0.3757  ,  0.310975,  0.300451,  0.069317],
     *              [ 0.361526,  0.455201,  0.515535, -0.155379],
     *              [ 0.      ,  0.      ,  0.      ,  1.      ]
     *          ],
     *          [
     *              [ 1.50793 ,  1.256797,  1.213523, -2.02222 ],
     *              [ 0.406074,  0.205106,  0.23734 ,  0.248555],
     *              [ 0.456527,  0.346317,  0.458883, -0.208346],
     *              [ 0.      ,  0.      ,  0.      ,  1.      ]
     *          ],
     *          [
     *              [ 1.267205,  1.551624,  1.470787, -2.100431],
     *              [ 0.419537,  0.390676,  0.292143,  0.10516 ],
     *              [ 0.380306,  0.452636,  0.50812 , -0.233582],
     *              [ 0.      ,  0.      ,  0.      ,  1.      ]
     *          ],
     *          [
     *              [ 2.229255,  2.2815  ,  2.300334, -3.430226],
     *              [ 0.494933,  0.557158,  0.508993, -0.241092],
     *              [ 0.740878,  0.695654,  0.728085, -0.608528],
     *              [ 0.      ,  0.      ,  0.      ,  1.      ]
     *          ]
     *      ]
     * 
     * 
     */

    torch::Tensor transformations;
    try {
        WorldTransformation worldTransformation;
        worldTransformation.setDevice(m__device);

        worldTransformation.setKinematicTree(kineTree);
        worldTransformation.setJoint(joints);
        worldTransformation.setPoseRotation(poseRotation);

        worldTransformation.transform();

        transformations = worldTransformation.getTransformation();
    }
    catch(std::exception &e) {
        std::cerr << e.what() << std::endl;
    }

    torch::Tensor slice = TorchEx::indexing(transformations,
        torch::IntList(), torch::IntList({0, 5}), torch::IntList());
    std::cout << "first five pose rotation: "
        << slice.sizes() << std::endl;// (1, 5, 4, 4)
    std::cout << slice << std::endl;

    std::cout << "PASS!" << std::endl;
    std::cout << "------------------------------------------------" << std::endl;

    BATCH_SIZE = batchSize;

    return;
}

/**linearBlendSkinning
 * 
 * Brief
 * ----------
 * 
 *      Test the <LinearBlendSkinng> module.
 * 
 * Arguments
 * ----------
 * 
 * 
 * Return
 * ----------
 * 
 * 
 * Notes
 * ----------
 * 
 *      We need to set both BATCH_SIZE and VERTEX_NUM in "definition/def.h" to 
 *      1 to make it compatible with this test.
 *      This kind of random number is generated by numpy with random seed 0.
 * 
 */
void Tester::linearBlendSkinning() noexcept(true)
{
    int batchSize = BATCH_SIZE;
    int vertexNum = VERTEX_NUM;
    BATCH_SIZE = 1;
    VERTEX_NUM = 1;


    std::cout << "---------- <LinearBlendSkinning> Test ----------" << std::endl;

    xt::xarray<float> weights_ {
        {
            0.5488135 , 0.71518937, 0.60276338, 0.54488318, 
            0.4236548 , 0.64589411, 0.43758721, 0.891773  , 
            0.96366276, 0.38344152, 0.79172504, 0.52889492,
            0.56804456, 0.92559664, 0.07103606, 0.0871293 , 
            0.0202184 , 0.83261985, 0.77815675, 0.87001215, 
            0.97861834, 0.79915856, 0.46147936, 0.78052918
        }
    };// (1, 24)
    torch::Tensor weights = torch::from_blob(weights_.data(),
        {BATCH_SIZE, JOINT_NUM}).to(m__device);

    xt::xarray<float> restShape_ {
        {
            {0.11827443, 0.63992102, 0.14335329}
        }
    };// (1, 1, 3)
    torch::Tensor restShape = torch::from_blob(restShape_.data(),
        {BATCH_SIZE, VERTEX_NUM, 3}).to(m__device);

    xt::xarray<float> transformations_ {
        {
            {
                {0.94466892, 0.52184832, 0.41466194, 0.26455561},
                {0.77423369, 0.45615033, 0.56843395, 0.0187898 },
                {0.6176355 , 0.61209572, 0.616934  , 0.94374808},
                {0.6818203 , 0.3595079 , 0.43703195, 0.6976312 }
            },

            {
                {0.06022547, 0.66676672, 0.67063787, 0.21038256},
                {0.1289263 , 0.31542835, 0.36371077, 0.57019677},
                {0.43860151, 0.98837384, 0.10204481, 0.20887676},
                {0.16130952, 0.65310833, 0.2532916 , 0.46631077}
            },
            {
                {0.24442559, 0.15896958, 0.11037514, 0.65632959},
                {0.13818295, 0.19658236, 0.36872517, 0.82099323},
                {0.09710128, 0.83794491, 0.09609841, 0.97645947},
                {0.4686512 , 0.97676109, 0.60484552, 0.73926358}
            },
            {
                {0.03918779, 0.28280696, 0.12019656, 0.2961402 },
                {0.11872772, 0.31798318, 0.41426299, 0.0641475 },
                {0.69247212, 0.56660145, 0.26538949, 0.52324805},
                {0.09394051, 0.5759465 , 0.9292962 , 0.31856895}
            },
            {
                {0.66741038, 0.13179786, 0.7163272 , 0.28940609},
                {0.18319136, 0.58651293, 0.02010755, 0.82894003},
                {0.00469548, 0.67781654, 0.27000797, 0.73519402},
                {0.96218855, 0.24875314, 0.57615733, 0.59204193}
            },
            {
                {0.57225191, 0.22308163, 0.95274901, 0.44712538},
                {0.84640867, 0.69947928, 0.29743695, 0.81379782},
                {0.39650574, 0.8811032 , 0.58127287, 0.88173536},
                {0.69253159, 0.72525428, 0.50132438, 0.95608363}
            },
            {
                {0.6439902 , 0.42385505, 0.60639321, 0.0191932 },
                {0.30157482, 0.66017354, 0.29007761, 0.61801543},
                {0.4287687 , 0.13547406, 0.29828233, 0.56996491},
                {0.59087276, 0.57432525, 0.65320082, 0.65210327}
            },
            {
                {0.43141844, 0.8965466 , 0.36756187, 0.43586493},
                {0.89192336, 0.80619399, 0.70388858, 0.10022689},
                {0.91948261, 0.7142413 , 0.99884701, 0.1494483 },
                {0.86812606, 0.16249293, 0.61555956, 0.12381998}
            },
            {
                {0.84800823, 0.80731896, 0.56910074, 0.4071833 },
                {0.069167  , 0.69742877, 0.45354268, 0.7220556 },
                {0.86638233, 0.97552151, 0.85580334, 0.01171408},
                {0.35997806, 0.72999056, 0.17162968, 0.52103661}
            },
            {
                {0.05433799, 0.19999652, 0.01852179, 0.7936977 },
                {0.22392469, 0.34535168, 0.92808129, 0.7044144 },
                {0.03183893, 0.16469416, 0.6214784 , 0.57722859},
                {0.23789282, 0.934214  , 0.61396596, 0.5356328 }
            },
            {
                {0.58990998, 0.73012203, 0.311945  , 0.39822106},
                {0.20984375, 0.18619301, 0.94437239, 0.7395508 },
                {0.49045881, 0.22741463, 0.25435648, 0.05802916},
                {0.43441663, 0.31179588, 0.69634349, 0.37775184}
            },
            {
                {0.17960368, 0.02467873, 0.06724963, 0.67939277},
                {0.45369684, 0.53657921, 0.89667129, 0.99033895},
                {0.21689698, 0.6630782 , 0.26332238, 0.020651  },
                {0.75837865, 0.32001715, 0.38346389, 0.58831711}
            },
            {
                {0.83104846, 0.62898184, 0.87265066, 0.27354203},
                {0.79804683, 0.18563594, 0.95279166, 0.68748828},
                {0.21550768, 0.94737059, 0.73085581, 0.25394164},
                {0.21331198, 0.51820071, 0.02566272, 0.20747008}
            },
            {
                {0.42468547, 0.37416998, 0.46357542, 0.27762871},
                {0.58678435, 0.86385561, 0.11753186, 0.51737911},
                {0.13206811, 0.71685968, 0.3960597 , 0.56542131},
                {0.18327984, 0.14484776, 0.48805628, 0.35561274}
            },
            {
                {0.94043195, 0.76532525, 0.74866362, 0.90371974},
                {0.08342244, 0.55219247, 0.58447607, 0.96193638},
                {0.29214753, 0.24082878, 0.10029394, 0.01642963},
                {0.92952932, 0.66991655, 0.78515291, 0.28173011}
            },
            {
                {0.58641017, 0.06395527, 0.4856276 , 0.97749514},
                {0.87650525, 0.33815895, 0.96157015, 0.23170163},
                {0.94931882, 0.9413777 , 0.79920259, 0.63044794},
                {0.87428797, 0.29302028, 0.84894356, 0.61787669}
            },
            {
                {0.01323686, 0.34723352, 0.14814086, 0.98182939},
                {0.47837031, 0.49739137, 0.63947252, 0.36858461},
                {0.13690027, 0.82211773, 0.18984791, 0.51131898},
                {0.22431703, 0.09784448, 0.86219152, 0.97291949}
            },
            {
                {0.96083466, 0.9065555 , 0.77404733, 0.33314515},
                {0.08110139, 0.40724117, 0.23223414, 0.13248763},
                {0.05342718, 0.72559436, 0.01142746, 0.77058075},
                {0.14694665, 0.07952208, 0.08960303, 0.67204781}
            },
            {
                {0.24536721, 0.42053947, 0.55736879, 0.86055117},
                {0.72704426, 0.27032791, 0.1314828 , 0.05537432},
                {0.30159863, 0.26211815, 0.45614057, 0.68328134},
                {0.69562545, 0.28351885, 0.37992696, 0.18115096}
            },
            {
                {0.78854551, 0.05684808, 0.69699724, 0.7786954 },
                {0.77740756, 0.25942256, 0.37381314, 0.58759964},
                {0.2728219 , 0.3708528 , 0.19705428, 0.45985588},
                {0.0446123 , 0.79979588, 0.07695645, 0.51883515}
            },
            {
                {0.3068101 , 0.57754295, 0.95943334, 0.64557024},
                {0.03536244, 0.43040244, 0.51001685, 0.53617749},
                {0.68139251, 0.2775961 , 0.12886057, 0.39267568},
                {0.95640572, 0.18713089, 0.90398395, 0.54380595}
            },
            {
                {0.45691142, 0.88204141, 0.45860396, 0.72416764},
                {0.39902532, 0.90404439, 0.69002502, 0.69962205},
                {0.3277204 , 0.75677864, 0.63606106, 0.24002027},
                {0.16053882, 0.79639147, 0.9591666 , 0.45813883}
            },
            {
                {0.59098417, 0.85772264, 0.45722345, 0.95187448},
                {0.57575116, 0.82076712, 0.90884372, 0.81552382},
                {0.15941446, 0.62889844, 0.39843426, 0.06271295},
                {0.42403225, 0.25868407, 0.84903831, 0.03330463}
            },
            {
                {0.95898272, 0.35536885, 0.35670689, 0.0163285 },
                {0.18523233, 0.4012595 , 0.92929142, 0.09961493},
                {0.94530153, 0.86948853, 0.4541624 , 0.32670088},
                {0.23274413, 0.61446471, 0.03307459, 0.01560606}
            }
        }
    };// (1, 24, 4, 4)
    torch::Tensor transformations = torch::from_blob(transformations_.data(),
        {BATCH_SIZE, JOINT_NUM, 4, 4}).to(m__device);

    /**correct results
     * 
     * - vertices: (1, 1, 1)
     *      [
     *          [
     *              [1.077754, 1.091551, 1.083642]
     *          ]
     *      ]
     * 
     */

    torch::Tensor vertices;
    try {
        LinearBlendSkinning linearBlendSkinning;
        linearBlendSkinning.setDevice(m__device);

        linearBlendSkinning.setWeight(weights);
        linearBlendSkinning.setRestShape(restShape);
        linearBlendSkinning.setTransformation(transformations);

        linearBlendSkinning.skinning();

        vertices = linearBlendSkinning.getVertex();
    }
    catch(std::exception &e) {
        std::cerr << e.what() << std::endl;
    }

    std::cout << "posed vertices: "
        << vertices.sizes() << std::endl;// (N, 6890, 3)
    std::cout << vertices << std::endl;

    std::cout << "PASS!" << std::endl;
    std::cout << "------------------------------------------------" << std::endl;

    BATCH_SIZE = batchSize;
    VERTEX_NUM = vertexNum;

    return;
}

//=============================================================================
} // namespace smpl
//=============================================================================
